import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Menu } from '../database/entities/menu.entity';
import { CreateMenuDto, UpdateMenuDto, QueryMenusDto } from './dto/menus.dto';

@Injectable()
export class MenusService {
  constructor(
    @InjectRepository(Menu)
    private menusRepository: Repository<Menu>,
  ) {}

  async create(createMenuDto: CreateMenuDto): Promise<Menu> {
    const menu = this.menusRepository.create(createMenuDto);
    return this.menusRepository.save(menu);
  }

  async findAll(query: QueryMenusDto) {
    const { 
      page = 1, 
      pageSize = 10, 
      keyword, 
      name,
      path,
      type, 
      parentId,
      visible,
      status,
      createTimeStart,
      createTimeEnd,
      sortBy = 'sort',
      sortOrder = 'DESC'
    } = query;
    
    const queryBuilder = this.menusRepository.createQueryBuilder('menu')
      .leftJoinAndSelect('menu.parent', 'parent');

    // 关键词搜索（模糊匹配）
    if (keyword) {
      queryBuilder.andWhere(
        '(menu.name LIKE :keyword OR menu.path LIKE :keyword OR menu.remark LIKE :keyword)',
        { keyword: `%${keyword}%` }
      );
    }

    // 菜单名精确搜索
    if (name) {
      queryBuilder.andWhere('menu.name = :name', { name });
    }

    // 菜单路径搜索（模糊匹配）
    if (path) {
      queryBuilder.andWhere('menu.path LIKE :path', { path: `%${path}%` });
    }

    // 菜单类型筛选
    if (type) {
      queryBuilder.andWhere('menu.type = :type', { type });
    }

    // 父菜单筛选
    if (parentId !== undefined) {
      if (parentId === 0) {
        // 查询顶级菜单
        queryBuilder.andWhere('menu.parentId IS NULL');
      } else {
        queryBuilder.andWhere('menu.parentId = :parentId', { parentId });
      }
    }

    // 显示状态筛选
    if (visible !== undefined) {
      queryBuilder.andWhere('menu.visible = :visible', { visible });
    }

    // 启用状态筛选
    if (status !== undefined) {
      queryBuilder.andWhere('menu.status = :status', { status });
    }

    // 创建时间范围搜索
    if (createTimeStart) {
      queryBuilder.andWhere('DATE(menu.createTime) >= :createTimeStart', { 
        createTimeStart 
      });
    }

    if (createTimeEnd) {
      queryBuilder.andWhere('DATE(menu.createTime) <= :createTimeEnd', { 
        createTimeEnd 
      });
    }

    // 排序
    const allowedSortFields = ['sort', 'createTime', 'updateTime', 'name'];
    const orderBy = allowedSortFields.includes(sortBy) ? sortBy : 'sort';
    const orderDirection = sortOrder === 'ASC' ? 'ASC' : 'DESC';
    
    const [list, total] = await queryBuilder
      .orderBy(`menu.${orderBy}`, orderDirection)
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    return {
      list,
      total,
      page,
      pageSize,
    };
  }

  async getMenuTree(): Promise<Menu[]> {
    const menus = await this.menusRepository.find({
      where: { status: 1 },
      order: { sort: 'ASC', createTime: 'DESC' },
    });

    return this.buildMenuTree(menus);
  }

  private buildMenuTree(menus: Menu[], parentId: number | null = null): Menu[] {
    return menus
      .filter(menu => menu.parentId === parentId)
      .map(menu => ({
        ...menu,
        children: this.buildMenuTree(menus, menu.id),
      }));
  }

  async findById(id: number): Promise<Menu> {
    const menu = await this.menusRepository.findOne({
      where: { id },
      relations: ['parent', 'children'],
    });
    
    if (!menu) {
      throw new NotFoundException('菜单不存在');
    }
    
    return menu;
  }

  async update(id: number, updateMenuDto: UpdateMenuDto): Promise<Menu> {
    const menu = await this.findById(id);
    Object.assign(menu, updateMenuDto);
    return this.menusRepository.save(menu);
  }

  async remove(id: number): Promise<void> {
    const menu = await this.findById(id);
    
    const childrenCount = await this.menusRepository.count({
      where: { parentId: id },
    });
    
    if (childrenCount > 0) {
      throw new Error('请先删除子菜单');
    }
    
    await this.menusRepository.remove(menu);
  }
}